﻿namespace CatClient.Message.Spi.Heartbeat
{
    using CatClient.Message.Spi.Heartbeat.Extend;
    using CatClient.Util;
    using Microsoft.VisualBasic.Devices;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Management;
    using System.Runtime.CompilerServices;
    using System.Xml;
    using System.Xml.Schema;
    using System.Xml.Serialization;

    [XmlRoot("memory")]
    public class MemoryInfo : IRefresh, IXmlSerializable, IProcessPerformance
    {
        private readonly Stopwatch _stopwatch = new Stopwatch();
        private readonly int[] _gcCounts = new int[GC.MaxGeneration + 1];
        private readonly ComputerInfo _computerInfo;
        private readonly PerformanceCounter _perWorkingCounter;
        private long _max = -1L;

        public MemoryInfo()
        {
            this._stopwatch.Start();
            this._computerInfo = new ComputerInfo();
            this._perWorkingCounter = this.CurrentProcessCounter("Working Set - Private");
            this.GCInfoList = new List<GCInfo>();
            for (int i = 0; i <= GC.MaxGeneration; i++)
            {
                this._gcCounts[i] = GC.CollectionCount(i);
            }
            this._stopwatch.Stop();
            LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Info($"Heartbeat {"MemoryInfo"} init finish. {this._stopwatch.ElapsedMilliseconds}ms");
        }

        private float GetMemory()
        {
            this._stopwatch.Restart();
            float num = 0f;
            ManagementClass class2 = new ManagementClass("Win32_PhysicalMemory");
            ManagementObjectCollection instances = class2.GetInstances();
            foreach (ManagementBaseObject obj2 in instances)
            {
                num += (float) Convert.ToDouble(obj2.Properties["Capacity"].Value);
            }
            instances.Dispose();
            class2.Dispose();
            this._stopwatch.Stop();
            LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Info($"Heartbeat {"MemoryInfo"} {"GetMemory"} finish. {this._stopwatch.ElapsedMilliseconds}ms");
            return num;
        }

        public XmlSchema GetSchema() => 
            null;

        public void ReadXml(XmlReader reader)
        {
        }

        public void Refresh()
        {
            this._stopwatch.Restart();
            this.Total = ((long) this._perWorkingCounter.NextValue()) / 0x400L;
            this.HeapUse = GC.GetTotalMemory(false) / 0x400L;
            this.HeapUnUse = (this.Total - this.HeapUse) / 0x400L;
            this.Free = (long) (this._computerInfo.AvailablePhysicalMemory / ((ulong) 0x400L));
            this.GCInfoList.Clear();
            for (int i = 0; i <= GC.MaxGeneration; i++)
            {
                GCInfo item = new GCInfo {
                    Name = "Gen_" + i
                };
                int num2 = GC.CollectionCount(i);
                item.Count = num2 - this._gcCounts[i];
                item.Time = num2;
                this._gcCounts[i] = num2;
                this.GCInfoList.Add(item);
            }
            this._stopwatch.Stop();
            LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Info($"Heartbeat {"MemoryInfo"} refresh finish. {this._stopwatch.ElapsedMilliseconds}ms");
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteAttributeString("max", this.Max.ToString());
            writer.WriteAttributeString("total", this.Total.ToString());
            writer.WriteAttributeString("free", this.Free.ToString());
            writer.WriteAttributeString("heap-usage", this.HeapUse.ToString());
            writer.WriteAttributeString("non-heap-usage", this.HeapUnUse.ToString());
            foreach (GCInfo info in this.GCInfoList)
            {
                writer.WriteStartElement("gc");
                if (!string.IsNullOrEmpty(info.Name))
                {
                    writer.WriteAttributeString("name", info.Name.ToString());
                }
                writer.WriteAttributeString("count", info.Count.ToString());
                writer.WriteAttributeString("time", info.Time.ToString());
                writer.WriteEndElement();
            }
        }

        [XmlAttribute("max")]
        public long Max
        {
            get
            {
                if (this._max == -1L)
                {
                    this._max = ((long) this.GetMemory()) / 0x400L;
                }
                return this._max;
            }
        }

        [XmlAttribute("total")]
        public long Total { get; set; }

        [XmlAttribute("free")]
        public long Free { get; set; }

        [XmlAttribute("heap-usage")]
        public long HeapUse { get; set; }

        [XmlAttribute("non-heap-usage")]
        public long HeapUnUse { get; set; }

        [XmlElement("gc")]
        public List<GCInfo> GCInfoList { get; set; }
    }
}

